/* eslint-disable class-methods-use-this */
/*
 * @Author: Season
 * @Date: 2020-08-06 14:31:40
 * @LastEditTime: 2020-08-06 15:07:18
 * @FilePath: \blog-chain\src\blockChain.ts
 */
import * as crypto from 'crypto';
import Block from './block';

export default class BlockChain {
  blocks: Block[] = [];

  constructor() {
    this.blocks = [
      new Block(0, '0', Date.parse(new Date().toString()), 'genesis block'),
    ];
  }

  calculateHash(block: Block) {
    return crypto
      .createHash('sha256')
      .update(block.index + block.prevHash + block.time + block.data)
      .digest('hex');
  }

  getLatestBlock() {
    return this.blocks[this.blocks.length - 1];
  }

  generateNextBlock(data: string) {
    const latestBlock = this.getLatestBlock();
    const hashPrevBlock = this.calculateHash(latestBlock);
    return new Block(
      Number(this.blocks.length),
      hashPrevBlock,
      Date.parse(new Date().toString()),
      data,
    );
  }

  isValidNewBlock(newBlock: Block, prevBlock: Block): boolean {
    if (prevBlock.index !== newBlock.index - 1) {
      return false;
    }

    if (newBlock.prevHash !== prevBlock.hash) {
      return false;
    }

    const newHash = crypto
      .createHash('sha256')
      .update(newBlock.index + newBlock.prevHash + newBlock.time + newBlock.data)
      .digest('hex');

    if (newHash !== newBlock.hash) {
      return false;
    }

    return true;
  }

  addBlock(newBlock: Block) {
    if (this.isValidNewBlock(newBlock, this.getLatestBlock())) {
      this.blocks.push(newBlock);
    }
  }
}
